package com.hibegin.http.server.web;

import com.hibegin.http.server.config.ServerConfig;
import com.hibegin.http.server.impl.HttpRequest;
import com.hibegin.http.server.impl.HttpResponse;
import com.szwistar.common.ERR;
import com.szwistar.common.algorithm.MD5;
import com.szwistar.common.comm.HttpMultipartBodyParser.PartInfo;
import com.szwistar.common.datastruct.JsonObject;
import com.szwistar.common.datastruct.Utils;
import com.szwistar.common.os.FileUtils;
import com.szwistar.common.os.PathUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Map;


/**
 * 文件上传处理
 */
public class WebFileUploader implements Controller {
	static final Logger LOG = LoggerFactory.getLogger(WebFileUploader.class);

	public void fileupload(HttpRequest request, HttpResponse response) {
		Map<String, PartInfo> fileParts = request.getFileParts();
		if(fileParts == null || Utils.isEmpty(fileParts)) {
			response.renderCode(ERR.BAD_PARAM, "没有上传文件！");
			return;
		}

		// 文件上传信息:
		// key: 文件字段名
		// value: 上传文件保存路径
		JsonObject fileInfos = new JsonObject();

		// 逐个处理上传的文件
		for(PartInfo filePart: fileParts.values()) {
			JsonObject uploadInfo = handleFileUpload(request, response, filePart);
			// 有一个文件上传失败，就停止
			if(uploadInfo == null) { return; }
			// 保存上传文件返回信息
			fileInfos.put(filePart.name, uploadInfo);
		}

		// 返回各文件上传信息
		response.renderJson(fileInfos);
	}

	/**
	 * 处理文件上传
	 * @param filePart 文件上传信息
	 * @return 上传文件信息；如果出错，则返回 null
	 */
	private JsonObject handleFileUpload(HttpRequest request, HttpResponse response, PartInfo filePart) {
		// 文件数据
		byte[] fileData = filePart.data;
		// 空文件
		if(fileData == null) { fileData = new byte[0]; }

		// 如果有指定的文件名，则使用指定的文件名
		// !!! 注意：必须通过 "xxxRenameTo" 参数来指定文件名 !!!
		String filename = request.getParaToStr(filePart.name + "RenameTo", null);
		// 否则，根据服务器配置的上传文件命名方式，设置文件名
		int naming = request.getServerConfig().getUploadFileNaming();
		if(Utils.isEmpty(filename)) {
			if(naming == ServerConfig.UPLOAD_FILE_NAMING_KEEP) {
				// 使用原始文件名
				filename = filePart.filename;
				if(Utils.isEmpty(filename)) {
					return new JsonObject();
				}
			}
			else if(naming == ServerConfig.UPLOAD_FILE_NAMING_RANDOM) {
				// 使用随机文件名
				filename = Long.toString(Math.round(Math.random()*100000000)) + "." + PathUtils.getFileExtension(filename);
			}
			else if(naming == ServerConfig.UPLOAD_FILE_NAMING_MD5) {
				// 使用 MD5 文件名
				filename = Utils.bytesToHexString(MD5.get(fileData)) + "." + PathUtils.getFileExtension(filename);
			}
		}

		String dstFilePath = null;
		try {
			// 取得上传文件全路径
			File dstFile = new File(request.getServerConfig().getUploadPath(), filename);
			// 确保目录存在
			dstFile.getParentFile().mkdirs();
			dstFilePath = dstFile.getCanonicalPath();
			if(dstFile.exists()) {
				LOG.debug("上传文件 {} 已存在，将被覆盖！", dstFilePath);
			}

			LOG.debug("保存上传文件 {} ...", dstFilePath);
			FileUtils.writeFile(dstFile, fileData);
			LOG.debug("保存上传成功！");

			return new JsonObject(
				"serverPath", dstFilePath,
				"relativePath", filename,
				"originalFilename", filePart.filename,
				"size", fileData.length );
		} catch (Exception e) {
			response.renderCode(ERR.FILE_SAVE, "保存上传文件失败！\r\n\t" + e.getMessage());
			return null;
		}
	}
}
